﻿#pragma once


#include "Property/EditorPropertyViewModel.h"
#include "EditorReflectedPropertyViewModel.m.h"

class REditorObjectPropertyAbilityViewModel;
class REditorPropertyModel;
class REditorReflectedPropertyModel;
class RStaticMesh;
class RMaterial;
class RTexture2D;

RCLASS()
class REditorReflectedPropertyViewModel : public REditorPropertyViewModel
{
    ROBJECT

public:
    virtual void BindModel(TSharedObjectPtr<REditorPropertyModel> InModel
        ,TSharedObjectPtr<REditorObjectPropertyAbilityViewModel> InAbilityViewModel) override;

    TDelegate<void> OnListChanged;

    enum class EPropertyType
    {
        Invalid,
        Int64,
        Float,
        Bool,
        String,


        StaticMesh,
        Material,   

        Vector, 

    };


    float GetListHeight() const;

    int64_t GetLineItemNum() const;
    EPropertyType GetViewType(int64_t InIndex) const;
    float GetLineHeight(int64_t InIndex) const;
    float GetDepth(int64_t InIndex) const;
    CString GetPropertyName(int64_t InIndex) const;

    int64_t GetIntValue(int64_t InIndex) const;
    void SetIntValue(int64_t InIndex, int64_t InValue);

    float GetFloatValue(int64_t InIndex) const;
    void SetFloatValue(int64_t InIndex,float InValue);

    bool GetBoolValue(int64_t InIndex) const;
    void SetBoolValue(int64_t InIndex,bool InValue);

    CString GetStringValue(int64_t InIndex) const;
    void SetStringValue(int64_t InIndex,CString InValue);

    TSharedObjectPtr<RStaticMesh> GetStaticMeshValue(int64_t InIndex) const;
    void SetStaticMeshValue(int64_t InIndex,TSharedObjectPtr<RStaticMesh> InValue);

    TSharedObjectPtr<RMaterial> GetMaterialValue(int64_t InIndex) const;
    void SetMaterialValue(int64_t InIndex,TSharedObjectPtr<RMaterial> InValue);


    // bool IsSelectorShow(int64_t InIndex) const;
    // void SetIsSelectorShow(int64_t InIndex,bool InValue);

    bool HasExpandIcon(int64_t InIndex) const;
    TSharedObjectPtr<RTexture2D> GetExpandIcon(int64_t InIndex) const;
    void ToggleExpand(int64_t InIndex);
    int64_t GetSubNodeNum(int64_t InIndex) const;

    bool HasMoreOperationButton(int64_t InIndex) const;
    bool CanDelete(int64_t InIndex) const;
    void Delete(int64_t InIndex);
    bool CanInsert(int64_t InIndex) const;
    void Insert(int64_t InIndex);
    bool CanDuplicate(int64_t InIndex) const;
    void Duplicate(int64_t InIndex);


    void AddVectorItem(int64_t InIndex);
    void ClearVector(int64_t InIndex);


protected:
    TWeakObjectPtr<REditorReflectedPropertyModel> PropertyModel;
    TSharedObjectPtr<RTexture2D> ExpandedIcon;
    TSharedObjectPtr<RTexture2D> CollapsedIcon;

    enum class EOperationFlag
    {
        None=0b0000,
        Delete= 0b0001,
        Insert = 0b0010,
        Duplicate= 0b0100,
    };

    struct SPropertyValue
    {
        std::shared_ptr<SPropertyValue> Parent=nullptr;

        CType* Type=nullptr;





        CString DisplayName;
        int64_t Depth=0;
        EPropertyType ViewType=EPropertyType::Invalid;
        
        TVector<CString> PropertyPath;

        //even the sub node is not show, we still need to
        //determine is there a expand icon
        int64_t SubNodeNum=0;

        //is sub node visible
        bool bIsExpanded=false;

        int64_t IndexInParent=0;

        //is this node need a more operation button
        EOperationFlag OperationFlag=EOperationFlag::None;


        //值有两种情况：
        //1.值有固定地址，比如类的成员变量，直接通过地址访问
        //2.值没有固定地址，比如类的虚拟属性，需要通过属性的getter和setter访问
        //那么这种属性值就需要一个拥有者的地址和对应的属性来读取和设置值
        //并且不支持子节点

        //值地址，仅在值有固定地址时有效
        void* Value=nullptr;
        
        //值拥有者，仅在值没有固定地址时有效
        RObjectWeakPtr PropertyOwner=nullptr;
        //值对应的属性，仅在值没有固定地址时有效
        CProperty* Property=nullptr;

    };

    TVector<void*> ExendedPropertyValues;

    TVector<std::shared_ptr<SPropertyValue>> PropertyNodes;

    void UpdatePropertyNodes();

    void CreateAndAddPropertyNode(
        CProperty* InProperty
        , RObjectPtr InOwner
        , int64_t InDepth
    );

    std::shared_ptr<SPropertyValue> CreateAndAddPropertyNodeByValue(
        CType* InType
        , void* InValue
        ,const CString& InDisplayName
        , const CString & InPropertyName
        , std::shared_ptr<SPropertyValue> InParent 
    );

    REditorReflectedPropertyViewModel::EPropertyType ToViewType(CType* InType) const;

    float ListHeight=0;

};